﻿using SixLabors.ImageSharp.Formats.Tga;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using static System.Runtime.InteropServices.JavaScript.JSType;

namespace ImageTools
{
    internal class Turbojpeg
    {
        [DllImport("libturbojpeg/libturbojpeg.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr tj3Init(int initType);

        [DllImport("libturbojpeg/libturbojpeg.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr tj3LoadImage8(IntPtr handle, string filename,
                                       ref int width, int align, ref int height,
                                       ref int pixelFormat);

        [DllImport("libturbojpeg/libturbojpeg.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern int tj3Set(IntPtr handle, int param, int value);

        [DllImport("libturbojpeg/libturbojpeg.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern int tj3Compress8(IntPtr handle, IntPtr srcBuf,
                           int width, int pitch, int height, int pixelFormat,
                           ref IntPtr jpegBuf, ref int jpegSize);

        [DllImport("libturbojpeg/libturbojpeg.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern void tj3Free(IntPtr buffer);

        [DllImport("libturbojpeg/libturbojpeg.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr tj3GetErrorStr(IntPtr handle);

        [DllImport("libturbojpeg/libturbojpeg.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern int tj3Decompress8(IntPtr handle, IntPtr jpegBuf,
                             int jpegSize, IntPtr dstBuf, int pitch,
                             int pixelFormat);

        [DllImport("libturbojpeg/libturbojpeg.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern int tj3DecompressHeader(IntPtr handle,
                                  IntPtr jpegBuf,
                                  int jpegSize);

        [DllImport("libturbojpeg/libturbojpeg.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern int tj3Get(IntPtr handle, int param);

        [DllImport("libturbojpeg/libturbojpeg.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern int tj3EncodeYUVPlanes8(IntPtr handle, IntPtr srcBuf,
                            int width, int pitch, int height, int pixelFormat,
                            IntPtr[] dstBuf, IntPtr strides);

        [DllImport("libturbojpeg/libturbojpeg.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern int tj3YUVBufSize(int width, int align, int height, int subsamp);

        [DllImport("libturbojpeg/libturbojpeg.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern void tj3Destroy(IntPtr handle);

        [DllImport("libturbojpeg/libturbojpeg.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern int tj3YUVPlaneSize(int componentID, int width, int stride,
                                 int height, int subsamp);
        /**
         * Chrominance subsampling options.
         * When pixels are converted from RGB to YCbCr (see #TJCS_YCbCr) or from CMYK
         * to YCCK (see #TJCS_YCCK) as part of the JPEG compression process, some of
         * the Cb and Cr (chrominance) components can be discarded or averaged together
         * to produce a smaller image with little perceptible loss of image clarity.
         * (The human eye is more sensitive to small changes in brightness than to
         * small changes in color.)  This is called "chrominance subsampling".
         */
        enum TJSAMP
        {
            /**
             * 4:4:4 chrominance subsampling (no chrominance subsampling).  The JPEG or
             * YUV image will contain one chrominance component for every pixel in the
             * source image.
             */
            TJSAMP_444,
            /**
             * 4:2:2 chrominance subsampling.  The JPEG or YUV image will contain one
             * chrominance component for every 2x1 block of pixels in the source image.
             */
            TJSAMP_422,
            /**
             * 4:2:0 chrominance subsampling.  The JPEG or YUV image will contain one
             * chrominance component for every 2x2 block of pixels in the source image.
             */
            TJSAMP_420,
            /**
             * Grayscale.  The JPEG or YUV image will contain no chrominance components.
             */
            TJSAMP_GRAY,
            /**
             * 4:4:0 chrominance subsampling.  The JPEG or YUV image will contain one
             * chrominance component for every 1x2 block of pixels in the source image.
             *
             * @note 4:4:0 subsampling is not fully accelerated in libjpeg-turbo.
             */
            TJSAMP_440,
            /**
             * 4:1:1 chrominance subsampling.  The JPEG or YUV image will contain one
             * chrominance component for every 4x1 block of pixels in the source image.
             * JPEG images compressed with 4:1:1 subsampling will be almost exactly the
             * same size as those compressed with 4:2:0 subsampling, and in the
             * aggregate, both subsampling methods produce approximately the same
             * perceptual quality.  However, 4:1:1 is better able to reproduce sharp
             * horizontal features.
             *
             * @note 4:1:1 subsampling is not fully accelerated in libjpeg-turbo.
             */
            TJSAMP_411,
            /**
             * 4:4:1 chrominance subsampling.  The JPEG or YUV image will contain one
             * chrominance component for every 1x4 block of pixels in the source image.
             * JPEG images compressed with 4:4:1 subsampling will be almost exactly the
             * same size as those compressed with 4:2:0 subsampling, and in the
             * aggregate, both subsampling methods produce approximately the same
             * perceptual quality.  However, 4:4:1 is better able to reproduce sharp
             * vertical features.
             *
             * @note 4:4:1 subsampling is not fully accelerated in libjpeg-turbo.
             */
            TJSAMP_441,
            /**
             * Unknown subsampling.  The JPEG image uses an unusual type of chrominance
             * subsampling.  Such images can be decompressed into packed-pixel images,
             * but they cannot be
             * - decompressed into planar YUV images,
             * - losslessly transformed if #TJXOPT_CROP is specified, or
             * - partially decompressed using a cropping region.
             */
            TJSAMP_UNKNOWN = -1
        };

        /**
         * Pixel formats
         */
        enum TJPF
        {
            /**
             * RGB pixel format.  The red, green, and blue components in the image are
             * stored in 3-sample pixels in the order R, G, B from lowest to highest
             * memory address within each pixel.
             */
            TJPF_RGB,
            /**
             * BGR pixel format.  The red, green, and blue components in the image are
             * stored in 3-sample pixels in the order B, G, R from lowest to highest
             * memory address within each pixel.
             */
            TJPF_BGR,
            /**
             * RGBX pixel format.  The red, green, and blue components in the image are
             * stored in 4-sample pixels in the order R, G, B from lowest to highest
             * memory address within each pixel.  The X component is ignored when
             * compressing and undefined when decompressing.
             */
            TJPF_RGBX,
            /**
             * BGRX pixel format.  The red, green, and blue components in the image are
             * stored in 4-sample pixels in the order B, G, R from lowest to highest
             * memory address within each pixel.  The X component is ignored when
             * compressing and undefined when decompressing.
             */
            TJPF_BGRX,
            /**
             * XBGR pixel format.  The red, green, and blue components in the image are
             * stored in 4-sample pixels in the order R, G, B from highest to lowest
             * memory address within each pixel.  The X component is ignored when
             * compressing and undefined when decompressing.
             */
            TJPF_XBGR,
            /**
             * XRGB pixel format.  The red, green, and blue components in the image are
             * stored in 4-sample pixels in the order B, G, R from highest to lowest
             * memory address within each pixel.  The X component is ignored when
             * compressing and undefined when decompressing.
             */
            TJPF_XRGB,
            /**
             * Grayscale pixel format.  Each 1-sample pixel represents a luminance
             * (brightness) level from 0 to the maximum sample value (255 for 8-bit
             * samples, 4095 for 12-bit samples, and 65535 for 16-bit samples.)
             */
            TJPF_GRAY,
            /**
             * RGBA pixel format.  This is the same as @ref TJPF_RGBX, except that when
             * decompressing, the X component is guaranteed to be equal to the maximum
             * sample value, which can be interpreted as an opaque alpha channel.
             */
            TJPF_RGBA,
            /**
             * BGRA pixel format.  This is the same as @ref TJPF_BGRX, except that when
             * decompressing, the X component is guaranteed to be equal to the maximum
             * sample value, which can be interpreted as an opaque alpha channel.
             */
            TJPF_BGRA,
            /**
             * ABGR pixel format.  This is the same as @ref TJPF_XBGR, except that when
             * decompressing, the X component is guaranteed to be equal to the maximum
             * sample value, which can be interpreted as an opaque alpha channel.
             */
            TJPF_ABGR,
            /**
             * ARGB pixel format.  This is the same as @ref TJPF_XRGB, except that when
             * decompressing, the X component is guaranteed to be equal to the maximum
             * sample value, which can be interpreted as an opaque alpha channel.
             */
            TJPF_ARGB,
            /**
             * CMYK pixel format.  Unlike RGB, which is an additive color model used
             * primarily for display, CMYK (Cyan/Magenta/Yellow/Key) is a subtractive
             * color model used primarily for printing.  In the CMYK color model, the
             * value of each color component typically corresponds to an amount of cyan,
             * magenta, yellow, or black ink that is applied to a white background.  In
             * order to convert between CMYK and RGB, it is necessary to use a color
             * management system (CMS.)  A CMS will attempt to map colors within the
             * printer's gamut to perceptually similar colors in the display's gamut and
             * vice versa, but the mapping is typically not 1:1 or reversible, nor can it
             * be defined with a simple formula.  Thus, such a conversion is out of scope
             * for a codec library.  However, the TurboJPEG API allows for compressing
             * packed-pixel CMYK images into YCCK JPEG images (see #TJCS_YCCK) and
             * decompressing YCCK JPEG images into packed-pixel CMYK images.
             */
            TJPF_CMYK,
            /**
             * Unknown pixel format.  Currently this is only used by #tj3LoadImage8(),
             * #tj3LoadImage12(), and #tj3LoadImage16().
             */
            TJPF_UNKNOWN = -1
        };

        /**
         * Parameters
         */
        enum TJPARAM
        {
            /**
             * Error handling behavior
             *
             * **Value**
             * - `0` *[default]* Allow the current compression/decompression/transform
             * operation to complete unless a fatal error is encountered.
             * - `1` Immediately discontinue the current
             * compression/decompression/transform operation if a warning (non-fatal
             * error) occurs.
             */
            TJPARAM_STOPONWARNING,
            /**
             * Row order in packed-pixel source/destination images
             *
             * **Value**
             * - `0` *[default]* top-down (X11) order
             * - `1` bottom-up (Windows, OpenGL) order
             */
            TJPARAM_BOTTOMUP,
            /**
             * JPEG destination buffer (re)allocation [compression, lossless
             * transformation]
             *
             * **Value**
             * - `0` *[default]* Attempt to allocate or reallocate the JPEG destination
             * buffer as needed.
             * - `1` Generate an error if the JPEG destination buffer is invalid or too
             * small.
             */
            TJPARAM_NOREALLOC,
            /**
             * Perceptual quality of lossy JPEG images [compression only]
             *
             * **Value**
             * - `1`-`100` (`1` = worst quality but best compression, `100` = best
             * quality but worst compression) *[no default; must be explicitly
             * specified]*
             */
            TJPARAM_QUALITY,
            /**
             * Chrominance subsampling level
             *
             * The JPEG or YUV image uses (decompression, decoding) or will use (lossy
             * compression, encoding) the specified level of chrominance subsampling.
             *
             * **Value**
             * - One of the @ref TJSAMP "chrominance subsampling options" *[no default;
             * must be explicitly specified for lossy compression, encoding, and
             * decoding]*
             */
            TJPARAM_SUBSAMP,
            /**
             * JPEG width (in pixels) [decompression only, read-only]
             */
            TJPARAM_JPEGWIDTH,
            /**
             * JPEG height (in pixels) [decompression only, read-only]
             */
            TJPARAM_JPEGHEIGHT,
            /**
             * JPEG data precision (bits per sample) [decompression only, read-only]
             *
             * The JPEG image uses the specified number of bits per sample.
             *
             * **Value**
             * - `8`, `12`, or `16`
             *
             * 12-bit data precision implies #TJPARAM_OPTIMIZE unless #TJPARAM_ARITHMETIC
             * is set.
             */
            TJPARAM_PRECISION,
            /**
             * JPEG colorspace
             *
             * The JPEG image uses (decompression) or will use (lossy compression) the
             * specified colorspace.
             *
             * **Value**
             * - One of the @ref TJCS "JPEG colorspaces" *[default for lossy compression:
             * automatically selected based on the subsampling level and pixel format]*
             */
            TJPARAM_COLORSPACE,
            /**
             * Chrominance upsampling algorithm [lossy decompression only]
             *
             * **Value**
             * - `0` *[default]* Use smooth upsampling when decompressing a JPEG image
             * that was compressed using chrominance subsampling.  This creates a smooth
             * transition between neighboring chrominance components in order to reduce
             * upsampling artifacts in the decompressed image.
             * - `1` Use the fastest chrominance upsampling algorithm available, which
             * may combine upsampling with color conversion.
             */
            TJPARAM_FASTUPSAMPLE,
            /**
             * DCT/IDCT algorithm [lossy compression and decompression]
             *
             * **Value**
             * - `0` *[default]* Use the most accurate DCT/IDCT algorithm available.
             * - `1` Use the fastest DCT/IDCT algorithm available.
             *
             * This parameter is provided mainly for backward compatibility with libjpeg,
             * which historically implemented several different DCT/IDCT algorithms
             * because of performance limitations with 1990s CPUs.  In the libjpeg-turbo
             * implementation of the TurboJPEG API:
             * - The "fast" and "accurate" DCT/IDCT algorithms perform similarly on
             * modern x86/x86-64 CPUs that support AVX2 instructions.
             * - The "fast" algorithm is generally only about 5-15% faster than the
             * "accurate" algorithm on other types of CPUs.
             * - The difference in accuracy between the "fast" and "accurate" algorithms
             * is the most pronounced at JPEG quality levels above 90 and tends to be
             * more pronounced with decompression than with compression.
             * - The "fast" algorithm degrades and is not fully accelerated for JPEG
             * quality levels above 97, so it will be slower than the "accurate"
             * algorithm.
             */
            TJPARAM_FASTDCT,
            /**
             * Optimized baseline entropy coding [lossy compression only]
             *
             * **Value**
             * - `0` *[default]* The JPEG image will use the default Huffman tables.
             * - `1` Optimal Huffman tables will be computed for the JPEG image.  For
             * lossless transformation, this can also be specified using
             * #TJXOPT_OPTIMIZE.
             *
             * Optimized baseline entropy coding will improve compression slightly
             * (generally 5% or less), but it will reduce compression performance
             * considerably.
             */
            TJPARAM_OPTIMIZE,
            /**
             * Progressive entropy coding
             *
             * **Value**
             * - `0` *[default for compression, lossless transformation]* The lossy JPEG
             * image uses (decompression) or will use (compression, lossless
             * transformation) baseline entropy coding.
             * - `1` The lossy JPEG image uses (decompression) or will use (compression,
             * lossless transformation) progressive entropy coding.  For lossless
             * transformation, this can also be specified using #TJXOPT_PROGRESSIVE.
             *
             * Progressive entropy coding will generally improve compression relative to
             * baseline entropy coding, but it will reduce compression and decompression
             * performance considerably.  Can be combined with #TJPARAM_ARITHMETIC.
             * Implies #TJPARAM_OPTIMIZE unless #TJPARAM_ARITHMETIC is also set.
             */
            TJPARAM_PROGRESSIVE,
            /**
             * Progressive JPEG scan limit for lossy JPEG images [decompression, lossless
             * transformation]
             *
             * Setting this parameter will cause the decompression and transform
             * functions to return an error if the number of scans in a progressive JPEG
             * image exceeds the specified limit.  The primary purpose of this is to
             * allow security-critical applications to guard against an exploit of the
             * progressive JPEG format described in
             * <a href="https://libjpeg-turbo.org/pmwiki/uploads/About/TwoIssueswiththeJPEGStandard.pdf" target="_blank">this report</a>.
             *
             * **Value**
             * - maximum number of progressive JPEG scans that the decompression and
             * transform functions will process *[default: `0` (no limit)]*
             *
             * @see #TJPARAM_PROGRESSIVE
             */
            TJPARAM_SCANLIMIT,
            /**
             * Arithmetic entropy coding
             *
             * **Value**
             * - `0` *[default for compression, lossless transformation]* The lossy JPEG
             * image uses (decompression) or will use (compression, lossless
             * transformation) Huffman entropy coding.
             * - `1` The lossy JPEG image uses (decompression) or will use (compression,
             * lossless transformation) arithmetic entropy coding.  For lossless
             * transformation, this can also be specified using #TJXOPT_ARITHMETIC.
             *
             * Arithmetic entropy coding will generally improve compression relative to
             * Huffman entropy coding, but it will reduce compression and decompression
             * performance considerably.  Can be combined with #TJPARAM_PROGRESSIVE.
             */
            TJPARAM_ARITHMETIC,
            /**
             * Lossless JPEG
             *
             * **Value**
             * - `0` *[default for compression]* The JPEG image is (decompression) or
             * will be (compression) lossy/DCT-based.
             * - `1` The JPEG image is (decompression) or will be (compression)
             * lossless/predictive.
             *
             * In most cases, compressing and decompressing lossless JPEG images is
             * considerably slower than compressing and decompressing lossy JPEG images,
             * and lossless JPEG images are much larger than lossy JPEG images.  Thus,
             * lossless JPEG images are typically used only for applications that require
             * mathematically lossless compression.  Also note that the following
             * features are not available with lossless JPEG images:
             * - Colorspace conversion (lossless JPEG images always use #TJCS_RGB,
             * #TJCS_GRAY, or #TJCS_CMYK, depending on the pixel format of the source
             * image)
             * - Chrominance subsampling (lossless JPEG images always use #TJSAMP_444)
             * - JPEG quality selection
             * - DCT/IDCT algorithm selection
             * - Progressive entropy coding
             * - Arithmetic entropy coding
             * - Compression from/decompression to planar YUV images
             * - Decompression scaling
             * - Lossless transformation
             *
             * @see #TJPARAM_LOSSLESSPSV, #TJPARAM_LOSSLESSPT
             */
            TJPARAM_LOSSLESS,
            /**
             * Lossless JPEG predictor selection value (PSV)
             *
             * **Value**
             * - `1`-`7` *[default for compression: `1`]*
             *
             * Lossless JPEG compression shares no algorithms with lossy JPEG
             * compression.  Instead, it uses differential pulse-code modulation (DPCM),
             * an algorithm whereby each sample is encoded as the difference between the
             * sample's value and a "predictor", which is based on the values of
             * neighboring samples.  If Ra is the sample immediately to the left of the
             * current sample, Rb is the sample immediately above the current sample, and
             * Rc is the sample diagonally to the left and above the current sample, then
             * the relationship between the predictor selection value and the predictor
             * is as follows:
             *
             * PSV | Predictor
             * ----|----------
             * 1   | Ra
             * 2   | Rb
             * 3   | Rc
             * 4   | Ra + Rb – Rc
             * 5   | Ra + (Rb – Rc) / 2
             * 6   | Rb + (Ra – Rc) / 2
             * 7   | (Ra + Rb) / 2
             *
             * Predictors 1-3 are 1-dimensional predictors, whereas Predictors 4-7 are
             * 2-dimensional predictors.  The best predictor for a particular image
             * depends on the image.
             *
             * @see #TJPARAM_LOSSLESS
             */
            TJPARAM_LOSSLESSPSV,
            /**
             * Lossless JPEG point transform (Pt)
             *
             * **Value**
             * - `0` through ***precision*** *- 1*, where ***precision*** is the JPEG
             * data precision in bits *[default for compression: `0`]*
             *
             * A point transform value of `0` is necessary in order to generate a fully
             * lossless JPEG image.  (A non-zero point transform value right-shifts the
             * input samples by the specified number of bits, which is effectively a form
             * of lossy color quantization.)
             *
             * @see #TJPARAM_LOSSLESS, #TJPARAM_PRECISION
             */
            TJPARAM_LOSSLESSPT,
            /**
             * JPEG restart marker interval in MCU blocks (lossy) or samples (lossless)
             * [compression only]
             *
             * The nature of entropy coding is such that a corrupt JPEG image cannot
             * be decompressed beyond the point of corruption unless it contains restart
             * markers.  A restart marker stops and restarts the entropy coding algorithm
             * so that, if a JPEG image is corrupted, decompression can resume at the
             * next marker.  Thus, adding more restart markers improves the fault
             * tolerance of the JPEG image, but adding too many restart markers can
             * adversely affect the compression ratio and performance.
             *
             * **Value**
             * - the number of MCU blocks or samples between each restart marker
             * *[default: `0` (no restart markers)]*
             *
             * Setting this parameter to a non-zero value sets #TJPARAM_RESTARTROWS to 0.
             */
            TJPARAM_RESTARTBLOCKS,
            /**
             * JPEG restart marker interval in MCU rows (lossy) or sample rows (lossless)
             * [compression only]
             *
             * See #TJPARAM_RESTARTBLOCKS for a description of restart markers.
             *
             * **Value**
             * - the number of MCU rows or sample rows between each restart marker
             * *[default: `0` (no restart markers)]*
             *
             * Setting this parameter to a non-zero value sets #TJPARAM_RESTARTBLOCKS to
             * 0.
             */
            TJPARAM_RESTARTROWS,
            /**
             * JPEG horizontal pixel density
             *
             * **Value**
             * - The JPEG image has (decompression) or will have (compression) the
             * specified horizontal pixel density *[default for compression: `1`]*.
             *
             * This value is stored in or read from the JPEG header.  It does not affect
             * the contents of the JPEG image.  Note that this parameter is set by
             * #tj3LoadImage8() when loading a Windows BMP file that contains pixel
             * density information, and the value of this parameter is stored to a
             * Windows BMP file by #tj3SaveImage8() if the value of #TJPARAM_DENSITYUNITS
             * is `2`.
             *
             * @see TJPARAM_DENSITYUNITS
             */
            TJPARAM_XDENSITY,
            /**
             * JPEG vertical pixel density
             *
             * **Value**
             * - The JPEG image has (decompression) or will have (compression) the
             * specified vertical pixel density *[default for compression: `1`]*.
             *
             * This value is stored in or read from the JPEG header.  It does not affect
             * the contents of the JPEG image.  Note that this parameter is set by
             * #tj3LoadImage8() when loading a Windows BMP file that contains pixel
             * density information, and the value of this parameter is stored to a
             * Windows BMP file by #tj3SaveImage8() if the value of #TJPARAM_DENSITYUNITS
             * is `2`.
             *
             * @see TJPARAM_DENSITYUNITS
             */
            TJPARAM_YDENSITY,
            /**
             * JPEG pixel density units
             *
             * **Value**
             * - `0` *[default for compression]* The pixel density of the JPEG image is
             * expressed (decompression) or will be expressed (compression) in unknown
             * units.
             * - `1` The pixel density of the JPEG image is expressed (decompression) or
             * will be expressed (compression) in units of pixels/inch.
             * - `2` The pixel density of the JPEG image is expressed (decompression) or
             * will be expressed (compression) in units of pixels/cm.
             *
             * This value is stored in or read from the JPEG header.  It does not affect
             * the contents of the JPEG image.  Note that this parameter is set by
             * #tj3LoadImage8() when loading a Windows BMP file that contains pixel
             * density information, and the value of this parameter is stored to a
             * Windows BMP file by #tj3SaveImage8() if the value is `2`.
             *
             * @see TJPARAM_XDENSITY, TJPARAM_YDENSITY
             */
            TJPARAM_DENSITYUNITS,
            /**
             * Memory limit for intermediate buffers
             *
             * **Value**
             * - the maximum amount of memory (in megabytes) that will be allocated for
             * intermediate buffers, which are used with progressive JPEG compression and
             * decompression, optimized baseline entropy coding, lossless JPEG
             * compression, and lossless transformation *[default: `0` (no limit)]*
             */
            TJPARAM_MAXMEMORY,
            /**
             * Image size limit [decompression, lossless transformation, packed-pixel
             * image loading]
             *
             * Setting this parameter will cause the decompression, transform, and image
             * loading functions to return an error if the number of pixels in the source
             * image exceeds the specified limit.  This allows security-critical
             * applications to guard against excessive memory consumption.
             *
             * **Value**
             * - maximum number of pixels that the decompression, transform, and image
             * loading functions will process *[default: `0` (no limit)]*
             */
            TJPARAM_MAXPIXELS
        };

        public static byte[] JpegGenJpegFromRGB888(byte[] rgbBuffer, int width, int height, int yuvMode)
        {
            IntPtr tHandler = tj3Init(2); // TurboJPEG初始化为解码和编码
            if (tHandler == IntPtr.Zero)
            {
                throw new Exception("tj3Init 初始化失败");
            }

            if (tj3Set(tHandler, 4, yuvMode) != 0)
            {
                IntPtr messagePtr = tj3GetErrorStr(tHandler);
                string message = Marshal.PtrToStringAnsi(messagePtr);
                Marshal.FreeHGlobal(messagePtr);
                tj3Destroy(tHandler);
                throw new Exception(message);
            }

            if (tj3Set(tHandler, 3, 95) != 0) // TJPARAM_QUALITY
            {
                IntPtr messagePtr = tj3GetErrorStr(tHandler);
                string message = Marshal.PtrToStringAnsi(messagePtr);
                Marshal.FreeHGlobal(messagePtr);
                tj3Destroy(tHandler);
                throw new Exception(message);
            }

            IntPtr jpgBuff = IntPtr.Zero;
            int jpgSize = 0;

            IntPtr rgbIntPtr = Marshal.AllocHGlobal(rgbBuffer.Length);
            if (rgbIntPtr == IntPtr.Zero)
            {
                tj3Destroy(tHandler);
                throw new Exception("rgb内存申请失败");
            }

            Marshal.Copy(rgbBuffer, 0, rgbIntPtr, rgbBuffer.Length);

            if (tj3Compress8(tHandler, rgbIntPtr, width, 0, height, (int)TJPF.TJPF_BGR,
                                 ref jpgBuff, ref jpgSize) != 0)
            {
                IntPtr messagePtr = tj3GetErrorStr(tHandler);
                string message = Marshal.PtrToStringAnsi(messagePtr);
                Marshal.FreeHGlobal(messagePtr);
                if (jpgBuff != IntPtr.Zero)
                {
                    tj3Free(jpgBuff);
                }

                Marshal.FreeHGlobal(rgbIntPtr);
                tj3Destroy(tHandler);
                throw new Exception(message);
            }

            Marshal.FreeHGlobal(rgbIntPtr);

            byte[] jpegBytes = new byte[jpgSize];
            Marshal.Copy(jpgBuff, jpegBytes, 0, jpgSize);
            tj3Free(jpgBuff);
            tj3Destroy(tHandler);

            return jpegBytes;
        }

        /**
         从RGB生成YUV
         */
        public static byte[] JpegGenYUVFromRGB888(byte[] rgbBuffer, int width, int height, int yuvMode)
        {
            IntPtr tHandler = tj3Init(2); // TurboJPEG初始化为解码和编码
            if (tHandler == IntPtr.Zero)
            {
                throw new Exception("tj3Init 初始化失败");
            }

            IntPtr rgbIntPtr = Marshal.AllocHGlobal(rgbBuffer.Length);
            if (rgbIntPtr == IntPtr.Zero)
            {
                tj3Destroy(tHandler);
                throw new Exception("rgb内存申请失败");
            }

            Marshal.Copy(rgbBuffer, 0, rgbIntPtr, rgbBuffer.Length);

            if (tj3Set(tHandler, 4, yuvMode) != 0)
            {
                IntPtr messagePtr = tj3GetErrorStr(tHandler);
                string message = Marshal.PtrToStringAnsi(messagePtr);
                Marshal.FreeHGlobal(messagePtr);

                tj3Destroy(tHandler);
                Marshal.FreeHGlobal(rgbIntPtr);
                throw new Exception(message);
            }

            int y_size = tj3YUVPlaneSize(0, width, 0, height, yuvMode);
            int u_size = tj3YUVPlaneSize(1, width, 0, height, yuvMode);
            int v_size = tj3YUVPlaneSize(2, width, 0, height, yuvMode);

            IntPtr yPlane = Marshal.AllocHGlobal(y_size);
            IntPtr uPlane = Marshal.AllocHGlobal(u_size);
            IntPtr vPlane = Marshal.AllocHGlobal(v_size);

            IntPtr[] yuvIntPtr = { yPlane, uPlane, vPlane };

            if (tj3EncodeYUVPlanes8(tHandler, rgbIntPtr, width, 0, height, (int)TJPF.TJPF_BGR, yuvIntPtr, IntPtr.Zero) != 0)
            {
                IntPtr messagePtr = tj3GetErrorStr(tHandler);
                string message = Marshal.PtrToStringAnsi(messagePtr);
                
                Marshal.FreeHGlobal(messagePtr);
                Marshal.FreeHGlobal(rgbIntPtr);

                Marshal.FreeHGlobal(yPlane);
                Marshal.FreeHGlobal(uPlane);
                Marshal.FreeHGlobal(vPlane);

                tj3Destroy(tHandler);
                throw new Exception(message);
            }

            Marshal.FreeHGlobal(rgbIntPtr);

            int yuvLength = y_size + u_size + v_size;

            byte[] yuvBytes = new byte[yuvLength];
            Marshal.Copy(yPlane, yuvBytes, 0, y_size);
            Marshal.Copy(uPlane, yuvBytes, y_size, u_size);
            Marshal.Copy(vPlane, yuvBytes, y_size + u_size, v_size);

            Marshal.FreeHGlobal(yPlane);
            Marshal.FreeHGlobal(uPlane);
            Marshal.FreeHGlobal(vPlane);

            tj3Destroy(tHandler);

            return yuvBytes;
        }
    }
}
